# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: xguo

import coin.exchange.base.kr_rest.level_book as level_book_mdl
import coin.exchange.base.kr_rest.public_client_base as pubcb
import coin.exchange.liqui_v3.kr_rest.native_public_client as npubc
from coin.exchange.liqui_v3.kr_rest.product import (
    get_active_symbol_list,
    LiquiProduct,
)

from coin.proto.coin_market_query_pb2 import ProductTicker, ExchangeTicker


def _parse_ticker(ticker, product):
  return ProductTicker(
      high=float(ticker['high']),
      low=float(ticker['low']),
      last=float(ticker['last']),
      ask=float(ticker['sell']),
      bid=float(ticker['buy']),
      volume_24hr=float(ticker['vol_cur']),  # Last rolling 24 hours.
      exchange_timestamp=int(float(ticker['updated']) * 1e+9),
      native_symbol=product.native_symbol,
      symbol=product.symbol)


class LiquiFeedParser(object):
  @staticmethod
  def parse_native_ticker(update_msg, product):
    """{
      "eth_btc": {
        "high": 109.88,
        "low": 91.14,
        "avg": 100.51,
        "vol": 1632898.2249,
        "vol_cur": 16541.51969,
        "last": 101.773,
        "buy": 101.9,
        "sell": 101.773,
        "updated": 1370816308
      }
      ...
    }"""
    ticker = None
    for native_symbol, ticker in update_msg.items():
      if product.native_symbol == native_symbol:
        break

    if ticker is None:
      raise ValueError('product not found!')
    return _parse_ticker(ticker, product)

  @staticmethod
  def parse_exchange_ticker(update_msg):
    ticker_list = []
    for native_symbol, ticker in update_msg.items():
      product = LiquiProduct.FromStrNativeProduct(native_symbol)
      ticker_list.append(_parse_ticker(ticker, product))
    return ExchangeTicker(
        exchange='Liqui',
        market_type='Spot',
        each_ticker=ticker_list,
    )

  @staticmethod
  def parse_level_book(update_msg, product):
    """ sample response:
    {
    "eth_btc":{
        "asks":[
            [103.426,0.01],
            [103.5,15],
            [103.504,0.425],
            [103.505,0.1],
            ...
        ],
        "bids":[
            [103.2,2.48502251],
            [103.082,0.46540304],
            [102.91,0.99007913],
            [102.83,0.07832332],
            ...
        ]
    }
    ...
    }
    """
    level_book = level_book_mdl.LevelBook(product)

    book_info = None
    for native_symbol, book_info in update_msg.items():
      if product.native_symbol == native_symbol:
        break

    if book_info is None:
      raise ValueError('product book not found!')

    for elem in book_info['asks']:
      level_elem = level_book_mdl.LevelElement(float(elem[0]), float(elem[1]), 0)
      level_book.add_ask(level_elem)

    for elem in book_info['bids']:
      level_elem = level_book_mdl.LevelElement(float(elem[0]), float(elem[1]), 0)
      level_book.add_bid(level_elem)
    level_book.finalize()
    return level_book


class LiquiPublicClient(pubcb.PublicClientBase):
  ProductType = LiquiProduct

  def __init__(self, timeout=1):
    self.npubc = npubc.LiquiNativePublicClient(timeout=timeout)

  def query_ticker_impl(self, product):
    symbol = product.native_symbol
    update = self.npubc.get_ticker(symbol)
    update.msg = LiquiFeedParser.parse_native_ticker(update.msg, product)
    return update

  def query_exchange_ticker_impl(self):
    symbol_list = get_active_symbol_list()
    update = self.npubc.get_ticker(symbol_list)
    update.msg = LiquiFeedParser.parse_exchange_ticker(update.msg)
    return update

  def query_level_book_impl(self, product):
    symbol = product.native_symbol
    update = self.npubc.get_orderbook(symbol)
    update.msg = LiquiFeedParser.parse_level_book(update.msg, product)
    return update
